package com.hejjon.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.hejjon.core.bean.TableColumn;
import com.hejjon.core.bean.TableField;
import com.hejjon.core.constant.SysConstants;
import com.hejjon.core.constant.TableFieldConstants;
import com.hejjon.core.domain.vo.RecordRelTableInfoVO;
import com.hejjon.core.enumer.DataViewTypeEnum;
import com.hejjon.core.enumer.DeleteFlagEnum;
import com.hejjon.core.enumer.JdbcTypeEnum;
import com.hejjon.core.exception.BusinessException;
import com.hejjon.core.utils.ExcelUtils;
import com.hejjon.core.utils.FileUtils;
import com.hejjon.core.utils.StrUtil;
import com.hejjon.domain.bo.RunInsertSqlBO;
import com.hejjon.domain.bo.RunQuerySqlBO;
import com.hejjon.domain.bo.RunSqlBO;
import com.hejjon.domain.bo.RunUpdateSqlBO;
import com.hejjon.domain.pojo.FilterCondition;
import com.hejjon.domain.request.LibraryDataQueryRequest;
import com.hejjon.domain.request.LibraryDataRequest;
import com.hejjon.domain.vo.FeatureFieldVO;
import com.hejjon.enumer.CompareOperatorEnum;
import com.hejjon.service.*;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import static com.hejjon.core.constant.SysConstants.*;
import static com.hejjon.core.constant.TableFieldConstants.*;

@Service
public class LibraryDataServiceImpl implements ILibaryDataService {

    private static final Logger log = LoggerFactory.getLogger(LibraryDataServiceImpl.class);

    @Resource
    private IFeatureFieldService featureFieldService;

    @Resource
    private IRecordRelTableInfoService recordRelTableInfoService;

    @Resource
    private ISysDatabaseService sysDatabaseService;

    @Resource
    private ISqlBuilderService sqlBuilderService;

    // 前端设置的行号字段的
    private static final String ROWNUM_FIELD_NAME = "rowNum";



    @Override
    public int batchSave(LibraryDataRequest request) {
        String recordId = request.getRecordId();
        String featureId = request.getFeatureId();
        JSONArray rowData = request.getRowData();

        int total = 0;
        Map<Boolean, List<JSONObject>> partitionMap = IntStream.range(0, rowData.size())
                .mapToObj(rowData::getJSONObject)
                .collect(Collectors.partitioningBy(row ->
                        row.containsKey("id") && StringUtils.isNotBlank(row.getString("id"))
                ));
        // 分出 新增插入的行数据和更新的行数据
        JSONArray insertRowData = new JSONArray(partitionMap.get(false));
        JSONArray updateRowData = new JSONArray(partitionMap.get(true));        // 含id字段并且不为null则是更新

        RecordRelTableInfoVO relVO = recordRelTableInfoService.getByRecordIdAndFeatureId(recordId, featureId);
        String tableName = relVO.getTableName();
        List<FeatureFieldVO> featureFieldVOList = featureFieldService.findByFeatureId(featureId);
        // 字段列表
        List<TableField> tableFieldList = featureFieldVOList.stream().map(f -> {
            TableField field = new TableField();
            field.setName(f.getName());
            field.setLabel(f.getLabel());
            field.setJdbcType(f.getJdbcType());
            field.setJavaType(f.getTypeName());
            field.setIsNumber(DataViewTypeEnum.getIsNumber(f.getJdbcType()));
            field.setIsDate(DataViewTypeEnum.getIsDate(f.getJdbcType()));
            field.setTableName(tableName);
            field.setIsCustom(true);        // 这些都是自定义字段
            return field;
        }).collect(Collectors.toList());

        RunSqlBO runSqlBO = sysDatabaseService.loadRunSqlBO(relVO.getDatabaseId());

        // 新增行
        if (!insertRowData.isEmpty()) {
            RunInsertSqlBO insertSqlBO = new RunInsertSqlBO(runSqlBO);
            List<Map<String, Object>> insertValueMapList = new ArrayList<>();
            for  (int i = 0; i < insertRowData.size(); i++) {
                JSONObject obj = insertRowData.getJSONObject(i);
                Integer rowNumVal = obj.getInteger(ROWNUM_FIELD_NAME);
                obj.put(FIELD_ROW_NUM, rowNumVal);
                obj.remove(ROWNUM_FIELD_NAME);
                insertValueMapList.add(obj);
            }
            insertSqlBO.setFieldList(tableFieldList);
            insertSqlBO.setValueList(insertValueMapList);
            // 填充默认字段值, 以下已将fieldList 字段修改, 加入了默认字段
            fillDefaultFiledsValue(insertSqlBO, request);
            String sql = sqlBuilderService.buildInsert(tableName, insertSqlBO.getFieldList(), insertSqlBO.getValueList());
            insertSqlBO.setSqlScript(sql);
            int insertCnt = sysDatabaseService.executeInsert(insertSqlBO);
            total += insertCnt;
        }

        // 更新行
        if (!updateRowData.isEmpty()) {
            RunUpdateSqlBO  updateSqlBO = new RunUpdateSqlBO(runSqlBO);
            List<Map<String, Object>> updateValueMapList = new ArrayList<>();
            for (int i = 0; i < updateRowData.size(); i++) {
                JSONObject row = updateRowData.getJSONObject(i);
                row.put(FIELD_UPDATE_TIME, new Date());
                updateValueMapList.add(row);
            }
            TableField updTimeField = new TableField();
            updTimeField.setName(FIELD_UPDATE_TIME);
            updTimeField.setLabel(UPDATE_TIME_COMMENT);
            updTimeField.setJdbcType(JdbcTypeEnum.DATETIME.getCode());
            updTimeField.setJavaType(JdbcTypeEnum.getJavaTypeBy(JdbcTypeEnum.DATETIME));
            updTimeField.setIsCustom(false);
            tableFieldList.add(updTimeField);
            updateSqlBO.setUpdateFieldList(tableFieldList);

            String sqlScript = sqlBuilderService.buildUpdate(tableName, tableFieldList);
            updateSqlBO.setSqlScript(sqlScript);
            updateSqlBO.setValueList(updateValueMapList);
            int updateCnt = sysDatabaseService.executeUpdate(updateSqlBO);
            total += updateCnt;
        }

        Connection connection = runSqlBO.getConnection();
        try {
            connection.close();
        } catch (SQLException e) {
            throw new BusinessException("关闭数据库连接失败, 异常信息: " + e.getMessage());
        }

        return total;
    }

    /**
     * 填充默认字段
     */
    private void fillDefaultFiledsValue(RunInsertSqlBO sqlBO, LibraryDataRequest request) {
        List<TableColumn> defaultColumnList = TableFieldConstants.getDefaultColumnList();
        List<TableField> defaultFileds = defaultColumnList.stream().map(TableField::ofDefault).collect(Collectors.toList());
        List<TableField> fieldList = sqlBO.getFieldList();
        fieldList.addAll(0, defaultFileds);
        List<Map<String, Object>> valueList = sqlBO.getValueList();
        for (Map<String, Object> rowMap : valueList) {
            Map<String, Object> map = new HashMap<>();
            for (TableField defField : defaultFileds) {
                String fieldName = defField.getName();
                Object fieldValue = null;
                switch (fieldName) {
                    case FIELD_ID:
                        fieldValue = StrUtil.getUUID();
                        break;
                    case FIELD_ROW_NUM:
                        fieldValue = rowMap.get(FIELD_ROW_NUM);
                        break;
                    case FIELD_PARENT_ID:
                        fieldValue = request.getNodeId();
                        break;
                    case FIELD_FEATURE_ID:
                        fieldValue = request.getFeatureId();
                        break;
                    case FIELD_DELETE_FLAG:     // 删除标记
                    case FIELD_UPDATE_TIME:     // 更新时间
                        fieldValue = defField.getValue();
                        break;
                    case FIELD_CREATE_TIME:     // 创建时间
                        fieldValue = new Date();
                }
                map.put(defField.getName(), fieldValue);
            }
            rowMap.putAll(map);
        }
    }


    @Override
    public List<Map<String, Object>> queryDataList(LibraryDataQueryRequest queryReq) {

        String nodeId = queryReq.getNodeId();
        String featureId = queryReq.getFeatureId();
        String recordId = queryReq.getRecordId();

        List<TableField> queryFieldList = new ArrayList<>();
        RecordRelTableInfoVO relVO = recordRelTableInfoService.getByRecordIdAndFeatureId(recordId, featureId);
        String tableName = relVO.getTableName();
        String databaseId = relVO.getDatabaseId();
        List<FeatureFieldVO> featureFieldVOList = featureFieldService.findByFeatureId(featureId);
        // 字段列表
        List<TableField> customFieldList = featureFieldVOList.stream().map(f -> {
            TableField field = new TableField();
            field.setName(f.getName());
            field.setLabel(f.getLabel());
            field.setJdbcType(f.getJdbcType());
            field.setJavaType(f.getTypeName());
            field.setIsNumber(DataViewTypeEnum.getIsNumber(f.getJdbcType()));
            field.setIsDate(DataViewTypeEnum.getIsDate(f.getJdbcType()));
            field.setTableName(tableName);
            field.setIsCustom(true);        // 这些都是自定义字段
            return field;
        }).collect(Collectors.toList());

        List<TableColumn> defaultColumnList = TableFieldConstants.getDefaultColumnList();
        List<TableField> defaultFiledList = defaultColumnList.stream().map(TableField::ofDefault).collect(Collectors.toList());
        queryFieldList.addAll(defaultFiledList);
        queryFieldList.addAll(customFieldList);

        RunSqlBO runSqlBO = sysDatabaseService.loadRunSqlBO(databaseId);
        RunQuerySqlBO querySqlBO = new RunQuerySqlBO(runSqlBO);

        List<TableField> defaultSortFields = getDefaultSortField();
        List<FilterCondition> conditionList = getDefaultConditionList(nodeId, featureId);
        String sql = sqlBuilderService.buildQueryScript(tableName, queryFieldList, conditionList, defaultSortFields);

        querySqlBO.setQueryFieldList(queryFieldList);
        querySqlBO.setSortFieldList(defaultSortFields);
        querySqlBO.setConditionList(conditionList);
        querySqlBO.setSqlScript(sql);

        return sysDatabaseService.executeQuery(querySqlBO);
    }


    /**
     * 默认排序字段
     * @return 默认排序字段列表
     */
    private static List<TableField> getDefaultSortField() {
        TableField tf = new TableField();
        tf.setName(FIELD_ROW_NUM);
        tf.setIsSort(true);
        tf.setDirection(SORT_ASC);
        List<TableField> sortFieldList = new ArrayList<>();
        sortFieldList.add(tf);
        return sortFieldList;
    }


    /**
     * 默认查询条件
     */
    private static List<FilterCondition> getDefaultConditionList(String nodeId, String featureId) {
        List<FilterCondition> conditionList = new ArrayList<>();
        FilterCondition cond1 = new FilterCondition(AND, FIELD_PARENT_ID, CompareOperatorEnum.EQ.getSymbol(), nodeId);
        FilterCondition cond2 = new FilterCondition(AND, FIELD_FEATURE_ID, CompareOperatorEnum.EQ.getSymbol(), featureId);
        FilterCondition cond3 = new FilterCondition(AND, FIELD_DELETE_FLAG, CompareOperatorEnum.EQ.getSymbol(), DeleteFlagEnum.NO.getCode());
        conditionList.add(cond1);
        conditionList.add(cond2);
        conditionList.add(cond3);
        return conditionList;
    }

    @Override
    public int logicDelte(LibraryDataRequest request) {
        String featureId = request.getFeatureId();
        String recordId = request.getRecordId();

        RecordRelTableInfoVO relVO = recordRelTableInfoService.getByRecordIdAndFeatureId(recordId, featureId);
        String tableName = relVO.getTableName();
        String databaseId = relVO.getDatabaseId();
        RunSqlBO runSqlBO = sysDatabaseService.loadRunSqlBO(databaseId);

        TableField idField = TableField.getInstance(FIELD_ID);
        TableField delFlagField = TableField.getInstance(FIELD_DELETE_FLAG);
        List<TableField> updateFieldList = new ArrayList<>();
        updateFieldList.add(idField);
        updateFieldList.add(delFlagField);

        List<String> ids = request.getIds();
        List<Map<String, Object>> updateValueMapList = new ArrayList<>();
        ids.forEach(id -> {
            Map<String, Object> valueMap = new HashMap<>();
            valueMap.put(FIELD_ID, id);
            valueMap.put(FIELD_DELETE_FLAG, DeleteFlagEnum.YES.getCode());
            updateValueMapList.add(valueMap);
        });

        RunUpdateSqlBO runUpdateSqlBO = new RunUpdateSqlBO(runSqlBO);
        String sql = sqlBuilderService.buildUpdate(tableName, updateFieldList);
        runUpdateSqlBO.setSqlScript(sql);
        runUpdateSqlBO.setValueList(updateValueMapList);
        runUpdateSqlBO.setUpdateFieldList(updateFieldList);

        return sysDatabaseService.executeUpdate(runUpdateSqlBO);
    }

    @Override
    public ResponseEntity<byte[]> downloadTemplate(String recordId, String featureId) {

        RecordRelTableInfoVO relVO = recordRelTableInfoService.getByRecordIdAndFeatureId(recordId, featureId);
        String featureLabel = relVO.getFeatureLabel();
        List<FeatureFieldVO> featureFieldVOList = featureFieldService.findByFeatureId(featureId);
        List<String> nameList = featureFieldVOList.stream().map(FeatureFieldVO::getLabel).collect(Collectors.toList());
        List<List<String>> headerList = nameList.stream().map(item -> {
            List<String> list = new ArrayList<>();
            list.add(item);
            return list;
        }).collect(Collectors.toList());
        byte[] bytes = ExcelUtils.writeOnlyHeader(headerList);
        return new ResponseEntity<>(bytes, FileUtils.getHttpHeaders(FileUtils.getFileName(featureLabel, ExcelUtils.EXCEL_FILE_SUFFIX)), HttpStatus.CREATED);
    }
}
